/**************************************************************************************************
*******
**************************************************************************************************/


/*******************************************************************************
* @file		pwm.c
* @brief	Contains all functions support for pwm driver
* @version	0.0
* @date		30. Oct. 2017
* @author	Ding
* 

*
*******************************************************************************/
#include "rom_sym_def.h"
#include "gpio.h"
#include "clock.h"
#include "pwm.h"
#include "pwrmgr.h"

/**************************************************************************************
 * @fn          hal_pwm_init
 *
 * @brief       This function process for pwm initial
 *
 * input parameters
 *
 * @param       PWMN_e pwmN						: pwm channel
 *              PWM_CLK_DIV_e pwmDiv			: clock prescaler of PWM channel
 *				PWM_CNT_MODE_e pwmMode			: count mode of PWM channel
 *				PWM_POLARITY_e pwmPolarity		: output polarity setting of PWM channel
 *				unsigned short cmpVal			: the compare value of PWM channel 
 *				unsigned short cntTopVal		: the counter top value of PWM channel
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void hal_pwm_init(
					PWMN_e pwmN,
					PWM_CLK_DIV_e pwmDiv,
					PWM_CNT_MODE_e pwmMode,
					PWM_POLARITY_e pwmPolarity)
{
    hal_clk_gate_enable(MOD_PWM);
    PWM_DISABLE_CH(pwmN);

    PWM_SET_DIV(pwmN, pwmDiv);
    PWM_SET_MODE(pwmN, pwmMode);
    PWM_SET_POL(pwmN, pwmPolarity);

    PWM_INSTANT_LOAD_CH(pwmN);
    hal_pwrmgr_register(MOD_PWM, NULL, NULL);
}

static gpio_pin_e pwm_gpio_map[]={
	GPIO_DUMMY,
	GPIO_DUMMY,
	GPIO_DUMMY,
	GPIO_DUMMY,
	GPIO_DUMMY,
	GPIO_DUMMY,
};
/**************************************************************************************
 * @fn          hal_pwm_open_channel
 *
 * @brief       This function process for pwm start working
 *
 * input parameters
 *
 * @param       PWMN_e pwmN						: pwm channel
 *              gpio_pin_e pwmPin				: pwm pin number
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void hal_pwm_open_channel(PWMN_e pwmN,gpio_pin_e pwmPin)
{
    hal_gpio_fmux_set(pwmPin, (gpio_fmux_e)(FMUX_PWM0 + pwmN));
    PWM_ENABLE_CH(pwmN);
    pwm_gpio_map[pwmN] = pwmPin;
}

/**************************************************************************************
 * @fn          hal_pwm_close_channel
 *
 * @brief       This function process for pwm stop working
 *
 * input parameters
 *
 * @param       PWMN_e pwmN						: pwm channel
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void hal_pwm_close_channel(PWMN_e pwmN)
{	
	if(pwm_gpio_map[pwmN] != GPIO_DUMMY)
    {
		hal_gpio_fmux(pwm_gpio_map[pwmN],Bit_DISABLE); 
		pwm_gpio_map[pwmN] = GPIO_DUMMY;
	}
	PWM_DISABLE_CH(pwmN);
}

/**************************************************************************************
 * @fn          hal_pwm_destroy
 *
 * @brief       This function process for pwm clear and disable
 *
 * input parameters
 *
 * @param       PWMN_e pwmN						: pwm channel
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void hal_pwm_destroy(PWMN_e pwmN)
{
    PWM_DISABLE_CH(pwmN);
    PWM_NO_LOAD_CH(pwmN);
    PWM_NO_INSTANT_LOAD_CH(pwmN);
	
    PWM_SET_DIV(pwmN, 0);
    PWM_SET_MODE(pwmN, 0);
    PWM_SET_POL(pwmN, 0);
		
    PWM_SET_TOP_VAL(pwmN, 0);
    PWM_SET_CMP_VAL(pwmN, 0);
}

/**************************************************************************************
 * @fn          hal_pwm_set_count_val
 *
 * @brief       This function process for change pwm count value
 *
 * input parameters
 *
 * @param       PWMN_e pwmN						: pwm channel
 *				uint16_t cmpVal					: the compare value of PWM channel 
 *				uint16_t cntTopVal				: the counter top value of PWM channel
 *
 * output parameters
 *
 * @param       None.
 *
 * @return      None.
 **************************************************************************************/
void hal_pwm_set_count_val(PWMN_e pwmN, uint16_t cmpVal, uint16_t cntTopVal)
{
	if(cmpVal > cntTopVal)
		return;	
	PWM_NO_LOAD_CH(pwmN);
	PWM_SET_CMP_VAL(pwmN, cmpVal);
	PWM_SET_TOP_VAL(pwmN, cntTopVal);
	PWM_LOAD_CH(pwmN);
}

static unsigned int pwm_en = 0;
void hal_pwm_start(void)
{
	if(pwm_en == 0)
	{
		hal_pwrmgr_lock(MOD_PWM);
		PWM_ENABLE_ALL;
		pwm_en = 1;
	}
}

void hal_pwm_stop(void)
{
	if(pwm_en == 1)
	{
		hal_pwrmgr_unlock(MOD_PWM);
		PWM_DISABLE_ALL;
		pwm_en = 0;
		hal_clk_gate_disable(MOD_PWM);
	}
}

//------------------------------------------------------------
//new api,make use easily
typedef struct {
    bool          enable;
    bool          ch_en[6];
    pwm_ch_t      ch[6];
}pwm_Ctx_t;

static pwm_Ctx_t pwmCtx = 
{
	.enable = FALSE,
	.ch_en = {FALSE,FALSE,FALSE,FALSE,FALSE,FALSE},
};

void hal_pwm_module_init(void)
{
	int i = 0;
		
	if(pwmCtx.enable == TRUE)
		return;
	pwmCtx.enable = TRUE;
	
	for(i = 0;i < 6;i++)
	{
		pwmCtx.ch_en[i] = FALSE;
		
		pwmCtx.ch[i].pwmN = (PWMN_e)i;		
		pwmCtx.ch[i].pwmPin = GPIO_DUMMY;		
		pwmCtx.ch[i].pwmDiv = PWM_CLK_NO_DIV;
		pwmCtx.ch[i].pwmMode = PWM_CNT_UP;
		pwmCtx.ch[i].pwmPolarity = PWM_POLARITY_RISING;
		pwmCtx.ch[i].cmpVal = 0;
		pwmCtx.ch[i].cntTopVal = 0;
		
		hal_pwm_destroy((PWMN_e)i);	
	}		
	
	hal_pwm_stop();
}

void hal_pwm_module_deinit(void)
{
	int i = 0;
		
	if(pwmCtx.enable == FALSE)
		return;
	pwmCtx.enable = FALSE;
	
	for(i = 0;i < 6;i++)
	{
		pwmCtx.ch_en[i] = FALSE;
		
		pwmCtx.ch[i].pwmN = (PWMN_e)i;		
		pwmCtx.ch[i].pwmPin = GPIO_DUMMY;		
		pwmCtx.ch[i].pwmDiv = PWM_CLK_NO_DIV;
		pwmCtx.ch[i].pwmMode = PWM_CNT_UP;
		pwmCtx.ch[i].pwmPolarity = PWM_POLARITY_RISING;
		pwmCtx.ch[i].cmpVal = 0;
		pwmCtx.ch[i].cntTopVal = 0;
		
		hal_pwm_close_channel((PWMN_e)i);
		hal_pwm_destroy((PWMN_e)i);	
	}	
	
	hal_pwm_stop();
}

void hal_pwm_ch_start(pwm_ch_t ch)
{
	if(pwmCtx.enable == FALSE)
		return;
	
	if(pwmCtx.ch_en[ch.pwmN] == TRUE)
	{
		hal_pwm_set_count_val(ch.pwmN,ch.cmpVal,ch.cntTopVal);
		PWM_SET_DIV(ch.pwmN, ch.pwmDiv);
	}
	else
	{
		hal_pwm_init(ch.pwmN,ch.pwmDiv,ch.pwmMode,ch.pwmPolarity);
		hal_pwm_set_count_val(ch.pwmN,ch.cmpVal,ch.cntTopVal);
		hal_pwm_open_channel(ch.pwmN,ch.pwmPin);
		pwmCtx.ch_en[ch.pwmN] = TRUE;

		hal_pwm_start();
	}
}
void hal_pwm_ch_start_config(pwm_ch_t ch)
{
	if(pwmCtx.enable == FALSE)
		return;
	
	if(pwmCtx.ch_en[ch.pwmN] == TRUE)
	{
		hal_pwm_set_count_val(ch.pwmN,ch.cmpVal,ch.cntTopVal);
		PWM_SET_DIV(ch.pwmN, ch.pwmDiv);
	}
	else
	{
		hal_pwm_init(ch.pwmN,ch.pwmDiv,ch.pwmMode,ch.pwmPolarity);
		hal_pwm_set_count_val(ch.pwmN,ch.cmpVal,ch.cntTopVal);
		hal_pwm_open_channel(ch.pwmN,ch.pwmPin);
		pwmCtx.ch_en[ch.pwmN] = TRUE;

//		hal_pwm_start();
	}
}
void hal_pwm_ch_stop(pwm_ch_t ch)
{
	if(pwmCtx.ch_en[ch.pwmN] == FALSE)
		return;
	else
	{
		pwmCtx.ch_en[ch.pwmN] = FALSE;		
		hal_pwm_destroy(ch.pwmN);	
		hal_pwm_close_channel(ch.pwmN);		
	}	
}

bool hal_pwm_ch_enable(PWMN_e pwmN)
{
	return pwmCtx.ch_en[pwmN];
}

pwm_ch_t hal_pwm_ch_reg(PWMN_e pwmN)
{
	return pwmCtx.ch[pwmN];
}
